package test0ne;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;

public class DateUtil {

    private static ThreadLocal<Calendar> threadLocalCalendar = new ThreadLocal<Calendar>();

    public final static String DATE_PATTERN_1 = "yyyyMMdd";

    public final static String DATETIME_PATTERN_1 = "yyyyMMddHHmmss";

    public final static String DATETIME_PATTERN_2 = "yyyy-MM-dd HH:mm:ss";

    public final static String YYYY_MM_DDHHMM = "yyyy-MM-dd HH:mm";

    public final static String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";

    /**
     * 取得当前时间
     *
     * @return 当前日期（Date）
     */
    public static Date getCurrentDate() {
        return new Date();
    }

    /**
     * 取得昨天此时的时间
     *
     * @return 昨天日期（Date）
     */
    public static Date getYesterdayDate() {
        return new Date(getCurTimeMillis() - 0x5265c00L);
    }

    /**
     * 取得过去i天的时间
     *
     * @param i
     *            过去时间天数
     * @return 昨天日期（Date）
     */
    public static Date getPastdayDate(int i) {
        return new Date(getCurTimeMillis() - 0x5265c00L * i);
    }

    /**
     * 取得过去i天的时间
     *
     * @param i
     *            过去时间天数
     * @return 昨天日期（Date）
     */
    public static Date getPastdayDate(Date date, int i) {
        return new Date(date.getTime() - 0x5265c00L * i);
    }

    /**
     * 取得当前时间的长整型表示
     *
     * @return 当前时间（long）
     */
    public static long getCurTimeMillis() {
        return System.currentTimeMillis();
    }

    public static Timestamp getCurTimestamp() {
        return new Timestamp(getCurTimeMillis());
    }

    /**
     * 取得当前时间的字符串类型yyyy-MM-dd HH:mm:ss
     *
     * @return 当前时间（yyyy-MM-dd HH:mm:ss）
     */
    public static String getCurrentDateStr() {
        return getCurFormatDate(DATETIME_PATTERN_2);
    }

    /**
     * 取得昨天时间的字符串类型yyyy-MM-dd HH:mm:ss
     *
     * @return 当前时间（yyyy-MM-dd HH:mm:ss）
     */
    public static String getYesterdayDateStr() {
        return getDate2LStr(getYesterdayDate());
    }

    /**
     * 取得当前时间的特定表示格式的字符串
     *
     * @param formatDate
     *            时间格式（如：yyyy/MM/dd hh:mm:ss）
     * @return 当前时间
     */
    public static String getCurFormatDate(String formatDate) {
        Date date = getCurrentDate();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(formatDate);
        return simpleDateFormat.format(date);
    }

    /**
     * 取得某日期时间的特定表示格式的字符串
     *
     * @param format
     *            时间格式
     * @param date
     *            某日期（Date）
     * @return 某日期的字符串
     */
    public static String getDate2Str(String format, Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(date);
    }

    /**
     * 将日期转换为长字符串（包含：年-月-日 时:分:秒）
     *
     * @param date
     *            日期
     * @return 返回型如：yyyy-MM-dd HH:mm:ss 的字符串
     */
    public static String getDate2LStr(Date date) {
        return getDate2Str(DATETIME_PATTERN_2, date);
    }

    /**
     * 将日期转换为长字符串（包含：年/月/日 时:分:秒）
     *
     * @param date
     *            日期
     * @return 返回型如：yyyy/MM/dd HH:mm:ss 的字符串
     */
    public static String getDate2LStr2(Date date) {
        return getDate2Str("yyyy/MM/dd HH:mm:ss", date);
    }

    /**
     * 将日期转换为中长字符串（包含：年-月-日 时:分）
     *
     * @param date
     *            日期
     * @return 返回型如：yyyy-MM-dd HH:mm 的字符串
     */
    public static String getDate2MStr(Date date) {
        return getDate2Str("yyyy-MM-dd HH:mm", date);
    }

    /**
     * 将日期转换为中长字符串（包含：年/月/日 时:分）
     *
     * @param date
     *            日期
     * @return 返回型如：yyyy/MM/dd HH:mm 的字符串
     */
    public static String getDate2MStr2(Date date) {
        return getDate2Str("yyyy/MM/dd HH:mm", date);
    }

    /**
     * 将日期转换为短字符串（包含：年-月-日）
     *
     * @param date
     *            日期
     * @return 返回型如：yyyy-MM-dd 的字符串
     */
    public static String getDate2SStr(Date date) {
        return getDate2Str("yyyy-MM-dd", date);
    }

    /**
     * 将日期转换为短字符串（包含：年/月/日）
     *
     * @param date
     *            日期
     * @return 返回型如：yyyy/MM/dd 的字符串
     */
    public static String getDate2SStr2(Date date) {
        return getDate2Str("yyyy/MM/dd", date);
    }

    /**
     * 取得型如：yyyyMMddhhmmss的字符串
     *
     * @param date
     * @return 返回型如：yyyyMMddhhmmss 的字符串
     */
    public static String getDate2All(Date date) {
        return getDate2Str(DATETIME_PATTERN_1, date);
    }

    /**
     * 取得型如：yyyyMMdd的字符串
     *
     * @param date
     * @return 返回型如：yyyyMMdd 的字符串
     */
    public static String getDate2YMDStr(Date date) {
        return getDate2Str(DATE_PATTERN_1, date);
    }

    /**
     * 取得型如：yyyyMMddhhmmss的字符串
     *
     * @param date
     * @return 返回型如：yyyyMMddhhmmss 的字符串
     */
    public static String getDate2Message(Date date) {
        return getDate2Str("MM月dd日HH:mm", date);
    }

    /**
     * 将长整型数据转换为Date后，再转换为型如yyyy-MM-dd HH:mm:ss的长字符串
     *
     * @param l
     *            表示某日期的长整型数据
     * @return 日期型的字符串
     */
    public static String getLong2LStr(long l) {
        Date date = getLongToDate(l);
        return getDate2LStr(date);
    }

    /**
     * 将长整型数据转换为Date后，再转换为型如yyyy-MM-dd的长字符串
     *
     * @param l
     *            表示某日期的长整型数据
     * @return 日期型的字符串
     */
    public static String getLong2SStr(long l) {
        Date date = getLongToDate(l);
        return getDate2SStr(date);
    }

    /**
     * 将长整型数据转换为Date后，再转换指定格式的字符串
     *
     * @param l
     *            表示某日期的长整型数据
     * @param formatDate
     *            指定的日期格式
     * @return 日期型的字符串
     */
    public static String getLong2SStr(long l, String formatDate) {
        Date date = getLongToDate(l);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(formatDate);
        return simpleDateFormat.format(date);
    }

    public static Date getStrToDate(String format, String str) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
            return simpleDateFormat.parse(str);
        } catch (ParseException e) {
//            log.error("", e);
        }
        return null;
    }

    /**
     * 将某指定的字符串转换为某类型的字符串
     *
     * @param format
     *            转换格式
     * @param str
     *            需要转换的字符串
     * @return 转换后的字符串
     */
    public static String getStr2Str(String format, String str) {
        Date date = getStrToDate(format, str);
        return getDate2Str(format, date);
    }

    /**
     * 将某指定的字符串转换为型如：yyyy-MM-dd HH:mm:ss的时间
     *
     * @param str
     *            将被转换为Date的字符串
     * @return 转换后的Date
     */
    public static Date getStr2LDate(String str) {
        return getStrToDate(DATETIME_PATTERN_2, str);
    }

    /**
     * 将某指定的字符串转换为型如：yyyy/MM/dd HH:mm:ss的时间
     *
     * @param format
     *            时间类型，如：yyyy-MM-dd HH:mm:ss
     * @param str
     *            将被转换为Date的字符串
     * @return 转换后的Date
     */
    public static Date getStr2LDate2(String format, String str) {
        return getStrToDate(format, str);
    }

    /**
     * 将某指定的字符串转换为型如：yyyy-MM-dd的时间
     *
     * @param str
     *            将被转换为Date的字符串
     * @return 转换后的Date
     */
    public static Date getStr2SDate(String str) {
        return getStrToDate("yyyy-MM-dd", str);
    }

    /**
     * 将某长整型数据转换为日期
     *
     * @param l
     *            长整型数据
     * @return 转换后的日期
     */
    public static Date getLongToDate(long l) {
        return new Date(l);
    }

    /**
     * 以分钟的形式表示某长整型数据表示的时间到当前时间的间隔
     *
     * @param l
     *            长整型数据
     * @return 相隔的分钟数
     */
    public static int getOffMinutes(long l) {
        return getOffMinutes(l, getCurTimeMillis());
    }

    /**
     * 以分钟的形式表示两个长整型数表示的时间间隔
     *
     * @param from
     *            开始的长整型数据
     * @param to
     *            结束的长整型数据
     * @return 相隔的分钟数
     */
    public static int getOffMinutes(long from, long to) {
        return (int) ((to - from) / 60000L);
    }

    private static Calendar getCalendar() {
        Calendar calendar = threadLocalCalendar.get();
        if (calendar == null) {
            calendar = Calendar.getInstance();
            threadLocalCalendar.set(calendar);
        }
        return calendar;
    }

    /**
     * 以微秒的形式赋值给一个Calendar实例
     *
     * @param l
     *            用来表示时间的长整型数据
     */
    public static void setCalendar(long l) {
        Calendar calendar = getCalendar();
        calendar.clear();
        calendar.setTimeInMillis(l);
    }

    /**
     * 以日期的形式赋值给某Calendar
     *
     * @param date
     *            指定日期
     */
    public static void setCalendar(Date date) {
        Calendar calendar = getCalendar();
        calendar.clear();
        calendar.setTime(date);
    }

    /**
     * 在此之前要由一个Calendar实例的存在
     *
     * @return 返回某年
     */
    public static int getYear(long millis) {
        Calendar instance = getCalendar();
        instance.setTimeInMillis(millis);
        return instance.get(1);
    }

    /**
     * 在此之前要由一个Calendar实例的存在
     *
     * @return 返回某月
     */
    public static int getMonth() {
        return getCalendar().get(2) + 1;
    }

    /**
     * 在此之前要由一个Calendar实例的存在
     *
     * @return 返回某天
     */
    public static int getDay() {
        return getCalendar().get(5);
    }

    /**
     * 在此之前要由一个Calendar实例的存在
     *
     * @return 返回某小时
     */
    public static int getHour() {
        return getCalendar().get(11);
    }

    /**
     * 在此之前要由一个Calendar实例的存在
     *
     * @return 返回某分钟
     */
    public static int getMinute() {
        return getCalendar().get(12);
    }

    /**
     * 在此之前要由一个Calendar实例的存在
     *
     * @return 返回某秒
     */
    public static int getSecond() {
        return getCalendar().get(13);
    }

    /**
     * dateTime格式:yyyy-MM-dd HH:mm:ss
     *
     * @param dateTime
     * @return
     * @throws ParseException
     */
    public static Timestamp stringToTimestamp(String dateTime) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN_2);
        Timestamp ts = new Timestamp(dateFormat.parse(dateTime).getTime());
        return ts;
    }

    public static Timestamp getStr2Timestamp(String dateStr, String pattern) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        Timestamp ts = new Timestamp(simpleDateFormat.parse(dateStr).getTime());
        return ts;
    }

    /**
     * 获取某月月份起始日期
     *
     * @param date
     *            yyyy-MM-dd
     * @return
     * @throws ParseException
     */
    public static String getMinMonthDate(String date, int offset) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFormat.parse(date));
        calendar.add(Calendar.MONTH, offset);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
        return dateFormat.format(calendar.getTime());
    }

    /**
     * 获取某月月份最后日期
     *
     * @param date
     *            yyyy-MM-dd
     * @return
     * @throws ParseException
     */
    public static String getMaxMonthDate(String date, int offset) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFormat.parse(date));
        calendar.add(Calendar.MONTH, offset);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return dateFormat.format(calendar.getTime());
    }

    /**
     * 获取一天之内的下个小时时间
     *
     * @param date
     *            yyyy-MM-dd HH:mm:ss
     * @return
     * @throws ParseException
     */
    public static Timestamp getNextHourByDay(String date, int nextHour) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN_2);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFormat.parse(date));
        calendar.add(Calendar.HOUR_OF_DAY, nextHour);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取一天之内的下个小时开始时间
     *
     * @param date
     *            yyyy-MM-dd HH:mm:ss
     * @param nextHour
     * @return
     * @throws ParseException
     */
    public static String getNextHourStartTimeByDay(String date, int nextHour) throws ParseException {
        date = date.substring(0, 14) + "00:00";
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN_2);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFormat.parse(date));
        calendar.add(Calendar.HOUR_OF_DAY, nextHour);
        return dateFormat.format(calendar.getTime());
    }

    /**
     * 获取一天之内的下个小时结束时间
     *
     * @param date
     *            yyyy-MM-dd HH:mm:ss
     * @param nextHour
     * @return
     * @throws ParseException
     */
    public static String getNextHourEndTimeByDay(String date, int nextHour) throws ParseException {
        date = date.substring(0, 14) + "59:59";
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN_2);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFormat.parse(date));
        calendar.add(Calendar.HOUR_OF_DAY, nextHour);
        return dateFormat.format(calendar.getTime());
    }

    /**
     * 获取一天之内的下个小时开始时间
     *
     * @param date
     *            yyyy-MM-dd HH:mm:ss
     * @param nextDay
     * @return yyyy-MM-dd HH:mm:ss
     * @throws ParseException
     */
    public static String getNextDayStartTime(String date, int nextDay) throws ParseException {
        date = date.substring(0, 10) + " 00:00:00";
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN_2);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFormat.parse(date));
        calendar.add(Calendar.DATE, nextDay);
        return dateFormat.format(calendar.getTime());
    }

    /**
     * 获取一天之内的下个小时结束时间
     *
     * @param date
     *            yyyy-MM-dd HH:mm:ss
     * @param nextDay
     * @return yyyy-MM-dd HH:mm:ss
     * @throws ParseException
     */
    public static String getNextDayEndTime(String date, int nextDay) throws ParseException {
        date = date.substring(0, 10) + " 23:59:59";
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN_2);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFormat.parse(date));
        calendar.add(Calendar.DATE, nextDay);
        return dateFormat.format(calendar.getTime());
    }

    /**
     * 获取几分钟之内的时间
     *
     * @param date
     *            yyyy-MM-dd HH:mm:ss
     * @param nextMin
     * @return
     * @throws ParseException
     */
    public static Date getNextMinTime(Date date, int nextMin) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, nextMin);
        return calendar.getTime();
    }

    /**
     * 获取几分钟之内的时间
     *
     * @param date
     *            yyyy-MM-dd HH:mm:ss
     * @param nextMin
     * @return
     * @throws ParseException
     */
    public static String getNextMinTime(String date, int nextMin) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN_2);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateFormat.parse(date));
        calendar.add(Calendar.MINUTE, nextMin);
        return dateFormat.format(calendar.getTime());
    }

    /**
     *
     */
    public static int compareByDay(Date fDate, Date oDate) {
        if (null == fDate || null == oDate) {
            return -1;
        }
        long intervalMilli = oDate.getTime() - fDate.getTime();
        return (int) (intervalMilli / (24 * 60 * 60 * 1000));
    }

    public static String getDateStart(String dateStr, String pattern) {
        Date date = getStrToDate(pattern, dateStr);
        return getDate2Str(DATETIME_PATTERN_2, date);
    }

    public static String getDateEnd(String dateStr, String pattern) {
        Date date = getStrToDate(pattern, dateStr);
        if(date == null) {
            return "";
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, 1);
        c.add(Calendar.SECOND, -1);

        return getDate2Str(DATETIME_PATTERN_2, c.getTime());
    }

    public static String getDateStart(long dateL) {
        Date date = getLongToDate(dateL);
        return getDate2Str(DATETIME_PATTERN_2, date);
    }

    public static String getDateEnd(long dateL) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(dateL);
        c.add(Calendar.DAY_OF_MONTH, 1);
        c.add(Calendar.SECOND, -1);

        return getDate2Str(DATETIME_PATTERN_2, c.getTime());
    }

    public static long getDateEndLong(long dateL) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(dateL);
        c.add(Calendar.DAY_OF_MONTH, 1);
        c.add(Calendar.SECOND, -1);

        return c.getTimeInMillis();
    }

    public static String getStr2Str(String dateStr, String srcPattern, String tarPattern) {
        Date date = getStrToDate(srcPattern, dateStr);
        return getDate2Str(tarPattern, date);
    }

    public static long getDateLong2Long(Long dateLong) {
        String dateStr = String.valueOf(dateLong);
        Date date = getStrToDate("yyyyMMdd", dateStr);
        return date.getTime();
    }

    public static long getDatetimeLong2Long(Long dateLong) {
        String dateStr = String.valueOf(dateLong);
        Date date = getStrToDate("yyyyMMddHHmmss", dateStr);
        return date.getTime();
    }

    public static int getDaysBetween(Timestamp before, Timestamp after) {
        long beforeLong = before.getTime();
        long afterLong = after.getTime();

        return Integer.parseInt(String.valueOf((afterLong - beforeLong) / (1000 * 3600 * 24)));
    }

    public static int getHoursBetween(Timestamp before, Timestamp after) {
        long beforeLong = before.getTime();
        long afterLong = after.getTime();

        return Integer.parseInt(String.valueOf((afterLong - beforeLong) / (1000 * 3600)));
    }

    public static int getMinsBetween(Timestamp before, Timestamp after) {
        long beforeLong = before.getTime();
        long afterLong = after.getTime();

        return Integer.parseInt(String.valueOf((afterLong - beforeLong) / (1000 * 60)));
    }

    public static int getWeekByCurrentTime() {
        return getWeekByTime(System.currentTimeMillis());
    }

    public static int getWeekByTime(long time) {
        int[] days = new int[] { 7, 1, 2, 3, 4, 5, 6 };
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(time));
        int i = calendar.get(Calendar.DAY_OF_WEEK);
        return days[i - 1];
    }

    public static String formatYYYY_MM_DD_HH_MM(Date time) {
//        Preconditions.checkNotNull(time);
        SimpleDateFormat dateFormat = new SimpleDateFormat(YYYY_MM_DD_HH_MM);
        return dateFormat.format(time);
    }

    public static Date addDays(Date date, int amount) {
//        Preconditions.checkNotNull(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DAY_OF_MONTH, amount);
        return cal.getTime();
    }

//    public static Date truncate(Date creatTime, int field) {
//        return org.apache.commons.lang3.time.DateUtils.truncate(creatTime, field);
//    }

    /**
     *
     * @param dateTime
     *            yyyy-MM-dd HH:mm:ss
     * @return 如果异常返回当前时间
     */
    public static Timestamp getTimestampByStr(String dateTime) {
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        try {
//            if (StringUtils.isNotBlank(dateTime)) {
//                Timestamp.valueOf(dateTime);
//            }
        } catch (Exception e) {
//            log.error("DateUtil getTimestampByStr Error!", e);
        }
        return timestamp;
    }

    /**
     *
     * @param dateTime
     *            yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String getDateStr(String dateTime) {
        return dateTime.substring(0, 10);
    }

    public static long getSecsBetween(Date fromTime,Date toTime){
        long from = fromTime.getTime()/1000;
        long to = toTime.getTime()/1000;
        return (to-from);
    }

    public static void main(String[] args) throws Exception {
        System.out.println(DateUtil.getNextDayStartTime(DateUtil.getCurrentDateStr(), -1));
        System.out.println(DateUtil.getNextDayStartTime(DateUtil.getCurrentDateStr(), 0));
        System.out.println(getYesterdayDateStr());
        System.out.println(DateUtil.getNextHourStartTimeByDay(DateUtil.getYesterdayDateStr(), -1));
        System.out.println(DateUtil.getNextHourStartTimeByDay(DateUtil.getYesterdayDateStr(), 0));

        System.out.println(new Date().compareTo(DateUtil.getStr2LDate("2021-04-12 00:00:00")));

//        long create = new Date("14:00:00").getTime();
//        long end = new Date().getTime();
//        long number = end - create;
//        DateFormat formatter = new SimpleDateFormat("hh:mm:ss");
//        Calendar calendar = Calendar.getInstance();
//        calendar.setTimeInMillis(number);
//        System.out.println(number+ " = " + formatter.format(calendar.getTime()));

        LocalDateTime localDateTime = LocalDateTime.now();
        String time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(localDateTime.minusDays(30L));
        System.out.println(time);
        System.out.println(time.substring(5,16));
//        System.out.println(DateFormat.getDateInstance().format());;

    }
}
